#pragma once

#include <iostream>

#include <unistd.h>

// shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

const char *g_path = "/root/linux_git_shortcut/IPC_Pipe_Signal";
int g_id = 0x666;
int g_size = 4096; // 建议给块大小的整数倍  一般是 4KB整数倍

// 设置 shm 权限
mode_t g_mode = 0600;

std::string toHex(int a)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%X", a);
    return buffer;
}

// 接口上 两个进程共享该类的方法，共享内存实例出一个便可
class ShareMemory
{
private:
    int CreateAuxiliary(int shmflg)
    {
        key_t k = ::ftok(g_path, g_id);
        if (k < 0)
        {
            std::cerr << "ftok error" << std::endl;
            return 1;
        }
        int shmid = ::shmget(k, g_size, shmflg);
        if (shmid < 0)
        {
            std::cerr << "shmget error" << std::endl;
            return 1;
        }
        std::cout << "shmid: " << shmid << std::endl;
        return shmid;
    }

public:
    ShareMemory() {}
    ~ShareMemory() {}

    int CreateShm()
    {
        return CreateAuxiliary(IPC_CREAT | IPC_EXCL | g_mode);
    }

    int GetShm()
    {
        return CreateAuxiliary(IPC_CREAT | g_mode);
    }

    void *AttachShm(int shmid)
    {
        void *addr = shmat(shmid, nullptr, 0);
        // error: cast from ‘void*’ to ‘int’ loses precision [-fpermissive]
        // std::cout << "addr: " << (int)addr << std::endl;
        // ok
        // std::cout << "addr: " << toHex((long long)addr) << std::endl;

        // 默认 64 位
        if ((long long)addr == -1)
        {
            return nullptr;
        }
        return addr;
    }

    void DetachShm(void *addr)
    {
        ::shmdt(addr);
        std::cout << "addr: " << toHex((long long)addr) << "detach success" << std::endl;
    }

    void DeleteShm(int shmid)
    {
        shmctl(shmid, IPC_RMID, nullptr);
    }

private:
}shm;